package asia.kalin.service.impl;

import asia.kalin.config.SnowflakeConfig;
import asia.kalin.domain.ao.Result;
import asia.kalin.domain.dto.CameraCollectionDTO;
import asia.kalin.domain.po.Camera;
import asia.kalin.domain.po.CameraCollection;
import asia.kalin.domain.po.DetectionResult;
import asia.kalin.domain.vo.CameraDetectionResultVO;
import asia.kalin.domain.vo.CameraListVO;
import asia.kalin.domain.vo.CameraVO;
import asia.kalin.enums.RedisKeyEnums;
import asia.kalin.mapper.CameraCollectionMapper;
import asia.kalin.mapper.CameraMapper;
import asia.kalin.mapper.DetectionResultMapper;
import asia.kalin.service.ICameraService;
import asia.kalin.utils.RedisLock;
import asia.kalin.utils.ThreadLocalUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Kalin
 * @since 2025-03-10
 */
@Service
@RequiredArgsConstructor
public class CameraServiceImpl extends ServiceImpl<CameraMapper, Camera> implements ICameraService {

    private final StringRedisTemplate stringRedisTemplate;

    private final DetectionResultMapper detectionResultMapper;

    private final CameraCollectionMapper cameraCollectionMapper;

    /**
     * 查询所有摄像头的位置及基本信息
     * @return Result
     */
    @Override
    public Result getCameraLocationList() {
        // 拼接key
        String key = RedisKeyEnums.CAMERA_INFO_LIST_KEY;
        // 查询redis
        String object = stringRedisTemplate.opsForValue().get(key);

        // 判断是否有值
        if(StrUtil.isNotBlank(object)){
            // 转换类型
            List<CameraListVO> cameraListVOList = JSONUtil.toList(object, CameraListVO.class);
            return new Result<>(0,"查询成功",cameraListVOList);
        }

        // 查询出所有摄像头
        List<CameraListVO> cameraListVOList = baseMapper.getCameraLocationList();
        // 转换成json
        // 创建一个JSONConfig对象
        JSONConfig config = new JSONConfig();
        // 设置日期格式
        config.setDateFormat("yyyy-MM-dd HH:mm:ss");
        String jsonStr = JSONUtil.toJsonStr(cameraListVOList,config);
        // 写入redis
        stringRedisTemplate.opsForValue().set(key,jsonStr,RedisKeyEnums.CAMERA_INFO_LIST_TTL, TimeUnit.HOURS);

        return new Result<>(0,"查询成功",cameraListVOList);
    }

    /**
     * 根据id查询出摄像头详情
     * @param cameraId 摄像头id
     * @return Result
     */
    @Override
    public Result queryCameraById(String cameraId) {
        // 拼接key
        String key = RedisKeyEnums.CAMERA_INFO_ID_KEY + cameraId;

        // 查询redis
        String object = stringRedisTemplate.opsForValue().get(key);
        if(StrUtil.isNotBlank(object)){
            // 转换类型
            CameraVO cameraVO = JSONUtil.toBean(object, CameraVO.class);
            return new Result<>(0,"查询成功",cameraVO);
        }

        // 查询数据库
        Camera camera = baseMapper.selectById(cameraId);
        if(camera == null){
            return new Result<>(1,"摄像头id不存在",null);
        }

        // 写入redis
        // 创建一个JSONConfig对象
        JSONConfig config = new JSONConfig();
        // 设置日期格式
        config.setDateFormat("yyyy-MM-dd HH:mm:ss");
        CameraVO cameraVO = BeanUtil.toBean(camera, CameraVO.class);
        String jsonStr = JSONUtil.toJsonStr(camera, config);
        stringRedisTemplate.opsForValue().set(key,jsonStr,RedisKeyEnums.CAMERA_INFO_ID_TTL,TimeUnit.HOURS);

        return new Result<>(0,"查询成功",cameraVO);
    }

    /**
     *查询出当前摄像头拍摄的所有检测结果信息
     * @param cameraId 摄像头id
     * @return Result
     */
    @Override
    public Result getResultListByCameraId(String cameraId) {
        // 拼接key
        String key = RedisKeyEnums.DETECTION_RESULT_BY_CAMERA_ID_KEY + cameraId;

        // 查询redis
        String object = stringRedisTemplate.opsForValue().get(key);
        if(StrUtil.isNotBlank(object)){
            // 转换类型
            List<CameraDetectionResultVO> cameraDetectionResultVOS = JSONUtil.toList(object, CameraDetectionResultVO.class);
            return new Result<>(0,"查询成功",cameraDetectionResultVOS);
        }

        // 没有 需要查询数据库
        List<DetectionResult> detectionResultList = detectionResultMapper.selectList(
                new QueryWrapper<DetectionResult>().eq("camera_id", cameraId)
        );
        if(detectionResultList == null || detectionResultList.isEmpty()){
            return new Result<>(1,"当前摄像头无检测信息或者摄像头id错误",null);
        }

        // 写入redis
        // 转换类型
        List<CameraDetectionResultVO> cameraDetectionResultVOS = BeanUtil.copyToList(detectionResultList, CameraDetectionResultVO.class);
        String jsonStr = JSONUtil.toJsonStr(cameraDetectionResultVOS);
        stringRedisTemplate.opsForValue().set(key,jsonStr,RedisKeyEnums.DETECTION_RESULT_BY_CAMERA_ID_TTL,TimeUnit.HOURS);

        return new Result<>(0,"查询成功",cameraDetectionResultVOS);
    }

    /**
     * 收藏摄像头id
     * @param collectionDTO 摄像头id
     * @return Result
     */
    @Override
    public Result collectionCameraLocation(CameraCollectionDTO collectionDTO) {
        // 得到当前用户id
        Map<String, Object> claims = ThreadLocalUtil.get();
        String userId = (String) claims.get("userId");

        // 拿锁
        RedisLock redisLock = new RedisLock(userId + collectionDTO.getCameraId(), stringRedisTemplate);
        boolean tryLock = redisLock.tryLock();
        if(!tryLock){
            return new Result<>(1,"其他人正在操作",null);
        }

        try {
            // 查询当前用户点赞记录
            CameraCollection cameraCollection = cameraCollectionMapper.selectOne(
                    new QueryWrapper<CameraCollection>().eq("user_id", userId).eq("camera_id", collectionDTO.getCameraId())
            );
            // 看用户是收藏 还是取消收藏
            if(collectionDTO.getIsCollection()){
                // 用户要收藏 但已经收藏过
                if(cameraCollection != null){
                    return new Result<>(1,"已经收藏过该地点",null);
                }

                // 创建点赞记录
                CameraCollection collection = new CameraCollection();
                collection.setCollectionId(String.valueOf(new SnowflakeConfig().snowflake().nextId()));
                collection.setCameraId(collectionDTO.getCameraId());
                collection.setUserId(userId);
                collection.setUpdateTime(LocalDateTime.now());
                collection.setCreateTime(LocalDateTime.now());

                // 插入数据库
                int insert = cameraCollectionMapper.insert(collection);
                if(insert <= 0){
                    return new Result<>(1,"收藏失败",null);
                }

                // 删除redis相关数据
                String key = RedisKeyEnums.CAMERA_LOCATION_COLLECTION_KEY + userId;
                stringRedisTemplate.delete(key);

                return new Result<>(0,"收藏成功",null);
            } else {
                // 用户要取消收藏 但未收藏过
                if(cameraCollection == null){
                    return new Result<>(1,"该地点本就没被收藏",null);
                }

                // 删除收藏
                int delete = cameraCollectionMapper.delete(
                        new QueryWrapper<CameraCollection>().eq("user_id", userId).eq("camera_id", collectionDTO.getCameraId())
                );

                if(delete <= 0){
                    return new Result<>(1,"取消收藏失败",null);
                }

                // 删除redis相关数据
                String key = RedisKeyEnums.CAMERA_LOCATION_COLLECTION_KEY + userId;
                stringRedisTemplate.delete(key);

                return new Result<>(0,"取消收藏成功",null);
            }
        } finally {
            redisLock.unlock();
        }
    }

    /**
     * 查询当前用户收藏的所有地点
     * @return Result
     */
    @Override
    public Result getUserCollectionCameraAll() {
        // 取出当前用户id
        Map<String,Object> claims = ThreadLocalUtil.get();
        String userId = (String) claims.get("userId");
        // 拼接key
        String key = RedisKeyEnums.CAMERA_LOCATION_COLLECTION_KEY + userId;
        // 查询redis
        String object = stringRedisTemplate.opsForValue().get(key);
        // 判断是否为空
        if(StrUtil.isNotBlank(object)){
            // 不是转换类型
            List<CameraListVO> cameraListVOList = JSONUtil.toList(object, CameraListVO.class);
            return new Result<>(0,"查询成功",cameraListVOList);
        }

        // redis不存在 查询数据库
        // 查询出当前用户收藏的cameraId
        List<CameraCollection> cameraCollections = cameraCollectionMapper.selectList(
                new QueryWrapper<CameraCollection>()
                        .eq("user_id", userId)
                        .select("camera_id")
        );
        List<String> cameraIds = cameraCollections.stream().map(CameraCollection::getCameraId).collect(Collectors.toList());
        if(cameraIds.isEmpty()){
            return new Result<>(1,"用户未收藏",null);
        }
        // 根据cameraIds查询出所有摄像头信息
        List<CameraListVO> cameraListVOList = baseMapper.getCameraLocationByCollection(cameraIds);

        // 转换json写入redis
        // 创建一个JSONConfig对象
        JSONConfig config = new JSONConfig();
        // 设置日期格式
        config.setDateFormat("yyyy-MM-dd HH:mm:ss");
        String jsonStr = JSONUtil.toJsonStr(cameraListVOList,config);
        stringRedisTemplate.opsForValue().set(key,jsonStr,RedisKeyEnums.CAMERA_LOCATION_COLLECTION_TTL,TimeUnit.HOURS);

        return new Result<>(0,"查询成功",cameraListVOList);
    }

    @Override
    public Result isCollectionById(String cameraId) {
        // 取出当前用户id
        Map<String,Object> claims = ThreadLocalUtil.get();
        String userId = (String) claims.get("userId");

        CameraCollection cameraCollection = cameraCollectionMapper.selectOne(
                new QueryWrapper<CameraCollection>()
                        .eq("user_id", userId)
                        .eq("camera_id", cameraId)
        );

        if(cameraCollection == null){
            return new Result<>(1,"未收藏",null);
        }

        return new Result<>(0,"已收藏",null);
    }
}
